/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.figures;

import static com.cea.papyrus.diagram.sequence.sedi.model.util.ModelUtil.neIsInstance;

import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.NodeEditPart;
import org.eclipse.gef.requests.CreateConnectionRequest;
import org.eclipse.gef.requests.ReconnectRequest;
import org.eclipse.uml2.uml.InteractionOperand;
import org.eclipse.uml2.uml.Message;

import com.cea.papyrus.diagram.sequence.sedi.editor.MessageSpecification;
import com.cea.papyrus.diagram.sequence.sedi.editor.SeparatorSpecification;
import com.cea.papyrus.diagraminterchange2.di2.GraphEdge;

/**
 * TODO Document
 * 
 * @author frankd@ifi.uio.no
 */
public class CombinedFragmentAnchorPolicy implements AnchorPolicy {
    private final CombinedFragmentFigure owner;

    public CombinedFragmentAnchorPolicy(final CombinedFragmentFigure owner) {
        this.owner = owner;
    }

    public boolean acceptConnectionCreate(ConnectionAnchor anchor, CreateConnectionRequest request) {
        final Object o = request.getNewObject();

        if (isMessage(o))
            return true; // Accept all messages

        else if (isSeparator(o)) {
            // Separators are accepted only conditionally:
            // 1. must begin on left edge of CF and (to avoid confusion)
            // a small distance above the bottom of the CF and
            // below the top of the CF
            Point anchorLocation = anchor.getLocation(null);
            Rectangle ownerBounds = owner.getBounds().getCopy();
            owner.translateToAbsolute(ownerBounds);
            return anchorLocation.x == ownerBounds.x
                    && anchorLocation.y < ownerBounds.bottom() - 10
                    && anchorLocation.y > ownerBounds.y + 20; // TODO calculate from
            // size of "pentagon"
        }

        return false;
    }

    public boolean acceptConnectionComplete(ConnectionAnchor anchor, CreateConnectionRequest request) {
        final Object o = request.getNewObject();
        if (isMessage(o)) {
            // TODO Support messages to self
            if (request.getSourceEditPart() == request.getTargetEditPart())
                return false;

            // TODO Verify that both ends belong to the same "interaction"
            // messages can't cross CF boundaries
            return true;
        }

        else if (isSeparator(o)) {
            // Separators are accepted only conditionally:
            // 1. must belong to same CF as start
            if (request.getSourceEditPart() != request.getTargetEditPart())
                return false;

            // 2. must end on right edge of CF
            Point anchorLocation = anchor.getLocation(null);
            Rectangle ownerBounds = owner.getBounds().getCopy();
            owner.translateToAbsolute(ownerBounds);
            if (anchorLocation.x != ownerBounds.right() - 1)
                return false;

            // 3. must be completely horizontal
            NodeEditPart sourceEP = (NodeEditPart) request.getSourceEditPart();
            ConnectionAnchor sourceAnchor = sourceEP.getSourceConnectionAnchor(request);
            Point sourceLocation = sourceAnchor.getLocation(null);
            return sourceLocation.y == anchorLocation.y;
        }

        return false;
    }

    public boolean acceptReconnectSource(final ConnectionAnchor anchor,
            final ReconnectRequest request) {

        final GraphEdge link = (GraphEdge) request.getConnectionEditPart().getModel();
        if (isMessage(link))
            return request.getTarget() != request.getConnectionEditPart().getTarget();

        else if (isSeparator(link)) {
            // Refuse sneaky attempt to move the separator start to the
            // right side.
            Point anchorLocation = anchor.getLocation(null);
            Rectangle ownerBounds = owner.getBounds().getCopy();
            owner.translateToAbsolute(ownerBounds);
            if (anchorLocation.x != ownerBounds.x)
                return false;

            // Currently we don't allow a separator to be moved to a different
            // CF either. TODO maybe allow this in the future
            if (request.getTarget() != request.getConnectionEditPart().getTarget())
                return false;

            return true;
        }

        return false;
    }

    public boolean acceptReconnectTarget(ConnectionAnchor anchor, ReconnectRequest request) {
        // Separators can't be moved at the target end
        GraphEdge link = (GraphEdge) request.getConnectionEditPart().getModel();
        if (isMessage(link))
            return request.getConnectionEditPart().getSource() != request.getTarget();
        else if (isSeparator(link))
            return false;

        return false;
    }

    private boolean isMessage(Object connection) {
        return (connection instanceof MessageSpecification || neIsInstance(connection,
                Message.class));
    }

    private boolean isSeparator(Object connection) {
        return (connection instanceof SeparatorSpecification || neIsInstance(connection,
                InteractionOperand.class));
    }
}
